perm filename REPLY.OLD[1,3]1 blob
sn#740285 filedate 1984-05-28 generic text, type T, neo UTF8
⊗⊂ DON Reply to mail
The REPLY macro makes it possible to send mail to whoever sent you a
particular piece of mail, without your having to type the network address or the
subject. You can also (optionally) include copies to all recipients of the
original message (optionally excluding "cc" recipients).
The basic operation of the macro is a three-step process. First, you
execute the REPLY macro. This sets up various headings based on the message on
the current page. (It's okay to have more than one in-core page, but results
are unspecified if there are multiple messages on one page.) The headings
should be self-explanatory. At the bottom of the page is the "reply text",
which is initially set up to be a line saying when the incoming message was sent
(if known) or received (if not). NOTE: If you have anything in the attach
buffer when you execute REPLY, the buffer set down as part of the reply text.
Having executed REPLY, you then edit the resulting template to add or
delete recipients and/or change the message text or subject. (Additional
recipients should be entered one per line with one of the prefaces "Also-To:"
or "Reply-cc:".) The only fields that must not be deleted entirely are the
"Replying-To" field (which must come first) and the "Reply-Text" field (which
must come last).
When you're done editing the message, you then type <control>% to
execute the % macro set up by REPLY (you're reminded of this by REPLY). This
sends the mail and restores the page to its original state.
If, after executing REPLY, you decide you don't really want to send
the reply at all, just do a CANCEL (or delete all the reply-related stuff).
To include all recipients of the original message on the mailing list
for the reply, execute the REPLY macro with an argument greater than 1. E.g.,
<control>2<control>ZREPLY<cr>. To include all but the "cc" recipients, give an
argument of "+", i.e., <control>+<control>ZREPLY<cr>. Doing either of these
also causes the initial reply-text to include the name of the original sender.
People listed as having received "remailed" copies of the message are considered
to be "cc" recipients.
Notes on operation: REPLY makes a good try at parsing the more common
of the hairy contructs permitted under RFC733, the document defining network
mail protocols. Quoted strings, parenthesised comments, and broketed network
addresses are all handled correctly. If the recipient list of the original
message lacks some host-names, the host of the original sender is assumed (some
sites' mailers fail to put full network addresses for "local" addressees), or
the host of the first "Remailed-from" entry, if the original sender has no host
specified. Foreign distribution-list files will probably be parsed correctly,
but the mail command will fail, since you can't access such files from here.
Local distribution lists, file destinations (#<file> construct), and forwarding
names (such as BUG-xxxx) should work.
During the "editing" phase (after executing REPLY but before executing
"%" to send the mail), the following three macros may be useful (they are loaded
in along with REPLY): CCME adds a "Reply-cc" to yourself. TOLIST deletes the
"Replying-To" line and changes the next line from "Also-To" or "Reply-cc" into
the Replylng-To line (this is for when the original message was sent to a
distribution list by someone on that list, and you want to reply to the list
without shipping the original sender an extra copy). OLDMSG appends the entire
text of the original message (header and all) to the end of the Reply-Text,
indented and set off by lines of hyphens.
If the mailing list is too large for E's command buffer (current limit
is about 160 characters), the % macro will create a temporary distribution-list
file and delete it after the mail is sent. This requires switching files, so
any changes made BEFORE executing REPLY will get written out -- the changes made
BY the REPLY macro are undone before switching. (If you're in READONLY mode,
then ALL changes are cancelled.)
REPLY and % are a bit slow, though fast enough for small mailing lists.
The slowest part may well be loading them in with EXECUTE! If you use REPLY
frequently, but don't want to wait for it to be loaded in every time you execute
your personal EINIT file for something else, you may want to create a macro
(say, R) that EXECUTEs this page of EINIT[1,3] and then does
<control>#<control>ZREPLY<cr>. With a little more hackery you could rig the R
macro to suppress the EXECUTE command on later calls -- e.g., have R invoke R1
to do the EXECUTE, and then replace R1 with some sort of "no-op".
REPLY and % leave most modes, such as STOPHOW and TERSE, unchanged. The
parenthesis characters for the "(" and ")" commands are changed (if necessary)
to be the default of "real" parentheses. The search-stop-line (SSLINE) value is
cleared, and the defaults for the search/substitute commands are changed. If it
was necessary to create a temporary distribution-list file, that file is left at
the bottom of the file stack. Various macro names are used for numeric values
and other temporary storage, and the % macro is of course overridden. The
undelete buffer size is unchanged; the undelete buffer is left holding the reply
subject and message text, such that an UNDELETE command retrieves them.
⊗⊃
αXDEFINE REPLY⊗↔
αZRENTRY⊗↔ ⊗; do our entry stuff (save modes, etc.)
αXSET REPLW=WFLAG.⊗↔ ⊗; remember whether W flag was on
αZREPL0⊗↔ ⊗; make sure blank line and no attach buffer
αβ#αZREPL1⊗↔ ⊗; put arg into REPARG for use by submacros
αXPAREN⊗↔ ⊗; make sure paren chars are "(" and ")"
αZRPMAIN⊗↔ ⊗; call main macro (this additional level
αZEXIT2⊗↔ ⊗; of nest makes aborting less noisy)
αβ⊗↓
αXDEFINE RENTRY⊗↔ ⊗; does entry stuff for REPLY and REPSND
⊗≠αZENTRYX⊗↔ ⊗; leave line-editor (if in), save modes
α-αXUNDELETE⊗↔ ⊗; speed things up a little more
αXSET REPLJC=CMAR.⊗↔αXSET REPLJL=LMAR.⊗↔αXSET REPLJR=RMAR.⊗↔ ⊗; JFILL info
αXSET REPLBK=BRKCOL.⊗↔αXSET REPDNT=INDENT.⊗↔ ⊗; BREAK and INDENT values (latter faked)
αβ⊗↓
αXDEFINE REXIT1⊗↔ ⊗; first stage of exit stuff (2nd is EXIT2)
αZEXIT1⊗↔
αXATTACH REPLJC⊗↔ ⊗; get a line to work with
αXJFILL REPLJC,REPLJL,REPLJR⊗↔ ⊗; restore justification parameters
αXINDENT REPDNT⊗↔ ⊗; restore indentation default
αXBREAK REPLBK⊗↔ ⊗; restore default break column
αβKαXSSLINE⊗↔ ⊗; discard junk line, clear search stop
αβ⊗↓
αXDEFINE RPMAIN⊗↔
αZREPL2⊗↔ ⊗; find sender
αZREPL3⊗↔ ⊗; find orig recipients if REPARG=+1 or >1
αZREPL4⊗↔ ⊗; find original cc names if REPARG > 1
αZREPL5⊗↔ ⊗; find subject
αZREPL6⊗↔ ⊗; put heading and preface on reply text
αZREPL7⊗↔ ⊗; set up macro % = REPSND
αZREXIT1⊗↔
αβ⊗↓
αXDEFINE REPLXX⊗↔ ⊗; error exit
αZREXIT1⊗↔
αXSET REPTMP=LINE.⊗↔
αXSTOPZERO⊗↔ ⊗; suppress error if no text to attach
αXARGUMENT REPLIN⊗↔αLα∞αβ!αA ⊗; restore attach buffer (if any)
αXSSLINE⊗↔
αXARGUMENT REPTMP⊗↔αL ⊗; now, where were we?
α-α1αXARGUMENT MDEPTH.⊗↔αXABORT⊗↔ ⊗; abort all but top level
αβ⊗↓
αXDEFINE REPL0⊗↔
α∞αLαXSET REPLIN=LINE.⊗↔ ⊗; go to bottom of incore page, save line #
α0αA ⊗; drop attach buffer, if any, as reply text
⊗↑α0αXNONEMPTY⊗↔⊗↔β⊗↔ ⊗; put in blank line if wasn't any
αXADD REPLIN⊗↔
αβ⊗↓
αXDEFINE REPL1⊗↔
αβ#αXSET REPARG⊗↔α2αXMULTIPLY REPARG⊗↔ ⊗; map 1 → 2, +1 → 3, >1 → >3
αZREPARG⊗↔α⊗→αXSET REPTMP=ASCII.⊗↔⊗≠ ⊗; enter line editor, then abort
α4α3αXIFEQ REPTMP⊗↔ ⊗; was first char of REPARG a "+"?
αXADD REPARG⊗↔ ⊗; if so, incr doubled value
αβ⊗↓
αXDEFINE REPL2⊗↔
αLαXEMPTY⊗↔α+α0αXSSLINE⊗↔ ⊗; searches stop before first blank line
αZREPL2A⊗↔ ⊗; look for right line in header
αZRFC733⊗↔ ⊗; parse RFC733 format, flush comments, etc.
αXARGUMENT REPLIN⊗↔αLαE ⊗; take copy of line down to bottom
αXADD REPLIN⊗↔ ⊗; old attach buffer now further down
⊗↔α1αβ⊗↔,αβUαXJOIN⊗↔ ⊗; put comma on the end
α1αXSIN⊗↔ ⊗; remove tabs (exist only if "∂" line)
αF,αβ\ ,⊗↔αXBREAK SRCHAR.⊗↔ ⊗; break ahead of first comma
⊗↔αβD⊗↑ ⊗; flush stuff from comma to end
α1αZREPNAM⊗↔ ⊗; parse what's left to form a name
α1αβ⊗↔⊗αI[In reply to message⊗α⊗β3⊗αXIFLE REPARG⊗⊗↔⊗αI from α⊗↔
α2αXREDEFINE REPFRM⊗↔αβD ⊗; save id of sender for "in reply to" text
αIReplying-To: α⊗↔ ⊗; add our special field name
αXSET REPLN2=LINE.⊗↔ ⊗; remember this position for REPLST
αβ⊗↓
αXDEFINE REPL2A⊗↔
αXSTOPZERO⊗↔αLαF⊗↓≡⊗↔Reply-To:⊗↓⊗↔⊗↔αXSET RPRPTO⊗↔ ⊗; flag name found on Reply-To line
αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔ ⊗; exit if found!
αXSTOPZERO⊗↔⊗↑αF⊗↓≡⊗↔From:⊗↓⊗↔⊗↔α0αXSET RPRPTO⊗↔
αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
⊗↑α1α5αXIFNE ASCII.⊗↔ ⊗; see if top line starts with "∂"
αXSAY Sorry -- Can't find sender's name anywhere in header.⊗↔
αZREPLXX⊗↔ ⊗; abort
αβ⊗↓
αXDEFINE REPL3⊗↔
α3αXIFLE REPARG⊗↔ ⊗; do "also-to"s only if arg was +1 or >1
αXSET RPLSTF←REPL3F⊗↔αXSET RPLSTI←REPL3I⊗↔ ⊗; set up things for REPLST
α1αZREPLST⊗↔αXIFEQ REPTOP⊗↔ ⊗; REPTOP=1 iff no "to"s found
αβXSAY Warning -- Unable to find any "To" lines.⊗↔
αβ⊗↓
αXDEFINE REPL3F⊗↔
αF⊗↓≡⊗↔To:⊗↓⊗↔
αβ⊗↓
αXDEFINE REPL3I⊗↔
αIAlso-to: α⊗↔
αβ⊗↓
αXDEFINE REPL4⊗↔
α4αXIFLE REPARG⊗↔ ⊗; send to cc's only if arg was >1
αXSET RPLSTF←REPL4F⊗↔αXSET RPLSTI←REPL4I⊗↔ ⊗; set up things for REPLST
α1αZREPLST⊗↔αXSET RPLSTF←REPL4G⊗↔ ⊗; find "cc"s, set up for "remailed-to"s
αXARGUMENT REPTOP⊗↔αZREPLST⊗↔αXIFEQ REPTOP⊗↔ ⊗; REPTOP=1 iff neither found
αβXSAY Warning -- Unable to find any "CC" lines.⊗↔
αβ⊗↓
αXDEFINE REPL4F⊗↔
αF⊗↓≡⊗↔cc:⊗↓⊗↔
αβ⊗↓
αXDEFINE REPL4G⊗↔
αF⊗↓≡⊗↔Remailed-To:⊗↓⊗↔
αβ⊗↓
αXDEFINE REPL4I⊗↔
αIReply-cc: α⊗↔
αβ⊗↓
αXDEFINE REPL5⊗↔
αXARGUMENT REPLN2⊗↔αXSSLINE⊗↔ ⊗; don't search reply text
αXSTOPZERO⊗↔⊗↔αLαF⊗↓≡⊗↔Subject:⊗↓⊗↔αXSTOPONE⊗↔ ⊗; look for RFC733 subject line
αXARGUMENT NFOUND.⊗↔αXCASE REPL5A REPL5B⊗↔
αXARGUMENT REPLIN⊗↔αLαE ⊗; take attached reply-subject down to our header
αXADD REPLIN⊗↔ ⊗; note movement downward of reply text
α+αXSSLINE⊗↔αFReply-Subject: re: re:αβ\Reply-Subject: re:⊗↔ ⊗; eschew redundant tautology
αβ⊗↓
αXDEFINE REPL5A⊗↔
αZREP5A0⊗↔ ⊗; try for "∂" line (aborts us if succeeds)
α1αβ⊗↔Reply-Subject: reply to messageαβA ⊗; couldn't find subject at all
αβ⊗↓
αXDEFINE REP5A0⊗↔
α1α5αXIFEQ ASCII.⊗↔ ⊗; check top line for "∂"
α+αXSSLINE⊗↔α2αF⊗=⊗↔ ⊗; does line include two tabs?
α+α1αXARGUMENT SRCHAR.⊗↔αXIFLT CHARS.⊗↔ ⊗; and does second tab have stuff after it?
αCαEαXSSLINE⊗↔αF⊗=αβ\ αβ2⊗↔ ⊗; a winner! copy it; tabs -> dbl-space
αXBREAK SRCHAR.⊗↔ ⊗; break between second pair of spaces
αβDα1αβ⊗↔Reply-Subject: re:α⊗↔αXJOIN⊗↔ ⊗; create our header line
αAαXTIN⊗↔αXSIN⊗↔ ⊗; flush trailing blanks
α2αXABORT⊗↔ ⊗; abort REPL5A
αβ⊗↓
αXDEFINE REPL5B⊗↔
⊗↔αCαEαFSubjectαβ\Reply-Subject: re⊗↔ ⊗; copy RFC733 subject line and make it ours
αA ⊗; pick it up
αβ⊗↓
αXDEFINE REPL6⊗↔
αXARGUMENT REPLIN⊗↔αLα3αβ⊗↔ ⊗; go to top of reply text and add header
⊗↔Reply-Text:⊗↔
α3αXADD REPLIN⊗↔ ⊗; that moved text down three lines
αZREPL6A⊗↔ ⊗; see if we can find date/time
αβD ⊗; delete junk line left by REP6A0 or REPL6A
αXARGUMENT REPLN2⊗↔αLαJ ⊗; go to top of reply headers and jump them
αXARGUMENT REPLIN⊗↔αL ⊗; move arrow to top of reply text
αβ⊗↓
αXDEFINE REPL6A⊗↔
αLαXARGUMENT REPLN2⊗↔αXSSLINE⊗↔ ⊗; don't search reply text
αXSTOPZERO⊗↔αF⊗↓≡⊗↔Date:⊗↓⊗↔αXSTOPONE⊗↔ ⊗; try to find RFC733 date line
αXARGUMENT NFOUND.⊗↔αXCASE REP6A0 REP6A1⊗↔
⊗; REP6A0 leaves us with attached date/time if found, else in line editor on junk line
⊗; REP6A1 always gives us attached date/time unless RFC733 aborts everything
⊗≠αXIFEQ ATTSIZ.⊗↔ ⊗; if nothing, abort; no big loss, so no error msg
αXARGUMENT REPLIN⊗↔αLαE ⊗; take it down to top of reply text
⊗↔β⊗↔α2αXADD REPLIN⊗↔ ⊗; separate it from reply text by blank line
α-αCαE ⊗; create junk line for REPL6 to delete
αβ⊗↓
αXDEFINE REP6A0⊗↔
αCαXJFILL 0,0,999⊗↔αE ⊗; copy line and flush tabs/multiple-spaces
α1α5αXIFEQ ASCII.⊗↔ ⊗; if top line is "∂", get its date/time
α1α6αXIFLE COLS.⊗↔ ⊗; line must have 16 cols if date/time there
αXBREAK 16⊗↔⊗↔αβD⊗↑ ⊗; flush rest of line
αDαβ4αβ8αXIFLE ASCII.⊗↔αβ5αβ7αXIFGE ASCII.⊗↔ ⊗; next char must be digit
αS αβ9αXIFEQ CHAR.⊗↔ ⊗; first "word" must be 9 chars ("dy-mon-yr")
α αβ4αβ8αXIFLE ASCII.⊗↔αβ5αβ7αXIFGE ASCII.⊗↔ ⊗; second "word" must start w/ digit
αS αβ1αβ4αXIFEQ CHAR.⊗↔ ⊗; second "word" must be 4 chars (time)
α⊗→αZREPFRM⊗↔αI rcvd α1α2α β:αS -PT.]αβA
αβ⊗↓
αXDEFINE REP6A1⊗↔
⊗↔α∞αZRFC733⊗↔ ⊗; move to "date" line, parse it (∞ = arg, not rep cnt)
αEα2αβ⊗↔ sent α⊗→αZREPFRM⊗↔α ⊗↔ ⊗; prepare enclosing text
.]αβA⊗↔αEα-α2αXJOIN⊗↔α1αXJFILL 0,0,999⊗↔ ⊗; combine preface and date
αXJOIN⊗↔αXSTOPZERO⊗↔α+αXSSLINE⊗↔αF..]αβ\.]αβ∞⊗↔αXSTOPONE⊗↔αA
αβ⊗↓
αXDEFINE REPL7⊗↔
αXSET %=REPSND⊗↔ ⊗; copy final-step macro to convenient name
αXSAY Type <control>% when ready to mail. ⊗↔
αβ⊗↓
αXDEFINE RFC733⊗↔
αZRFC1⊗↔ ⊗; handle "∂" lines specially
αCα∞αZRFC2⊗↔ ⊗; copy first line and all continuations
αEα+αXSSLINE⊗↔αXSTOPZERO⊗↔ ⊗; prepare to muck around on the one line
αF⊗=αβ\ αβ∞⊗↔ ⊗; all tabs become spaces
αXSTOPONE⊗↔⊗↑⊗↔αF:⊗↔ ⊗; find colon at end of header field name
αXBREAK SRCHAR.⊗↔ ⊗; break line so colon starts second line
αβDαF:αβ\⊗↔ ⊗; flush header name and colon
⊗⊂ now the tricky part: (1) flush parenthesised portions, which are
comments, but watch out for nesting and for quoted strings (quotes
inside parens are comments; parens in quotes are not!) (2) change
special chars <space>, <comma>, ":" and "@" in quotes to temporary
chars that won't screw up later parsing. main reason it's so tricky
is we're not sure line fits in line editor. ⊗⊃
β⊗↔α∞αZRFC3⊗↔ ⊗; create "collecting" line; handle parens
⊗↑αXJOIN⊗↔ ⊗; done parsing comments
β⊗↔α∞αZRFC4⊗↔ ⊗; create new collecting line; handle quotes
⊗↑αXJOIN⊗↔ ⊗; done parsing quoted strings
β⊗↔α#αZRFC5⊗↔ ⊗; create new collecting line; handle colons
⊗↑αXJOIN⊗↔ ⊗; done parsing <comment>:<text>; format
αXSTOPZEROα+αXSSLINE⊗↔αFεαβ\αβ∞⊗↔ ⊗; flush all the "ε"s that got added
αXSTOPONE⊗↔αA ⊗; pick up final version
αβ⊗↓
αXDEFINE RFC1⊗↔
α1α5αXIFEQ ASCII.⊗↔ ⊗; see if this is a "∂" line
αCαEα⊗=⊗=α⊗→αS⊗=αRαK⊗↔αA ⊗; yes; copy it, flush subject field
α2αXABORT⊗↔ ⊗; abort RFC733
αβ⊗↓
αXDEFINE RFC2⊗↔
α3α2αXIFEQ ASCII.⊗↔ ⊗; if next line starts with space, add it
α+αCαXJOIN⊗↔ ⊗; to attach buffer and join with rest
αβ⊗↓
αXDEFINE RFC3⊗↔
α+αXSSLINE⊗↔αF(αβ\ε(⊗↔ ⊗; find "(", done if none
αXBREAK SRCHAR.⊗↔ ⊗; break ahead of "("; "ε" ensures SRCHAR≠0
α+αXSSLINE⊗↔αXSTOPZERO⊗↔ ⊗; prepare to search up to "("
α∞αF"⊗↔αXSET REPTMP=NFOUND.⊗↔ ⊗; get number of quotes ahead of "("
αXSTOPONE⊗↔α2αXREMAINDER REPTMP⊗↔ ⊗; odd or even?
αXARGUMENT REPTMP⊗↔αXCASE RFC3A RFC3B⊗↔ ⊗; call subcase
αβ⊗↓
αXDEFINE RFC3A⊗↔
⊗↔αAαXSET REPTMP=LINE.⊗↔α∞αL ⊗; take line to bottom of page
α1αXBREAK 80⊗↔αE ⊗; break into bite-size chunks
αXSET REPTM2=LINE.⊗↔ ⊗; remember where first 80-char chunk is
αZRFC3A0⊗↔ ⊗; look for ")", return only if NOT found
αXSAY Sorry -- Couldn't find matching close parenthesis in above header line.⊗↔
αXARGUMENT REPTM2⊗↔αLα∞αβ!αβD ⊗; failed; clean up (∞! stops at pagemark)
αXARGUMENT REPTMP⊗↔αLα-α2αβD
αZREPLXX⊗↔
αβ⊗↓
αXDEFINE RFC3A0⊗↔
α) ⊗; find matching ")", abort if missing
αL⊗↔αDα⊗↔ ⊗; kill left to beginning of line, kill ")"
αXARGUMENT LINE.⊗↔αXSUBTRACT REPTM2⊗↔ ⊗; compute -# lines from "(" to here
αXARGUMENT REPTM2⊗↔αβD ⊗; delete all those lines
α∞αβ!αAα∞αXJOIN⊗↔ ⊗; pick up what's left (∞! stops at pagemark)
αXARGUMENT REPTMP⊗↔αLαE ⊗; put it back where we were
α-α2αXJOIN⊗↔ ⊗; join stuff left of "(" on collection line
⊗↔ ⊗; get back to working line
α2αXABORT⊗↔ ⊗; abort RFC3A
αβ⊗↓
αXDEFINE RFC3B⊗↔
⊗↔α+αXSSLINE⊗↔ ⊗; odd number of quotes, search for one more
αXSTOPZERO⊗↔αF"αβ\"ε⊗↔αXSTOPONE⊗↔ ⊗; handle failing search specially
α1αXARGUMENT NSUBST.⊗↔αZRFC3B0⊗↔ ⊗; REP3CY aborts if arg=1 (NSUBST=0)
αXBREAK SRCHAR.⊗↔ ⊗; break between " and ε
α2⊗↑α3αXJOIN⊗↔ ⊗; join through quote on collection line
⊗↔ ⊗; down to working line again
αβ⊗↓
αXDEFINE RFC3B0⊗↔
αXSET REPTMP⊗↔α#αXIFEQ REPTMP⊗↔ ⊗; abort if arg = 1
αXSAY Sorry -- Couldn't find matching quote in above header line.⊗↔
α2⊗↑α3αβD
αZREPLXX⊗↔
αβ⊗↓
αXDEFINE RFC4⊗↔
α+αXSSLINE⊗↔αF"αβ\ε"⊗↔ ⊗; find quote, done if none
αXBREAK SRCHAR.⊗↔ ⊗; break between quote and newly added "ε"
αXSTOPZERO⊗↔⊗↔α2αF"αβ\"ε⊗↔αXSTOPONE⊗↔ ⊗; find close quote (SSLINE still okay)
α1αXARGUMENT NSUBST.⊗↔αZRFC3B0⊗↔ ⊗; abort if couldn't find it
αXBREAK SRCHAR.⊗↔ ⊗; break between close quote and "ε"
α+αXSSLINE⊗↔αXSTOPZERO⊗↔ ⊗; prepare to change special chars (if any)
⊗↑⊗↔αF αβ\∧αβ∞⊗↔ ⊗; space becomes logical-and
⊗↑⊗↔αF,αβ\∨αβ∞⊗↔ ⊗; comma becomes logical-or
⊗↑⊗↔αF:αβ\∃αβ∞⊗↔ ⊗; colon becomes there-exists
⊗↑⊗↔αF@αβ\∀αβ∞⊗↔ ⊗; atsign becomes forall
αXSTOPONE⊗↔
α2⊗↑α3αXJOIN⊗↔ ⊗; join thru close-quote on collecting line
⊗↔ ⊗; back to the working line
αβ⊗↓
αXDEFINE RFC5⊗↔
α#αXIFLE CHARS.⊗↔α∞αZRFC5A⊗↔ ⊗; if arg=∞, parsing date; let colons be
αβ⊗↓
αXDEFINE RFC5A⊗↔
α+αXSSLINE⊗↔αF:αβ\εε⊗↔ ⊗; find colon, done if none, flush if there
αXBREAK SRCHAR.⊗↔ ⊗; break between the two newly-added "ε"s
αβ⊗↔,α⊗↔αXJOIN⊗↔α+αXSSLINE⊗↔ ⊗; make sure at least one comma before colon
αXSTOPZERO⊗↔α∞αF,⊗↔ ⊗; find last comma (if any) before colon
αXSTOPONE⊗↔αXARGUMENT NFOUND.⊗↔αF,αβ\,ε⊗↔
αXBREAK SRCHAR.⊗↔⊗↑⊗↔αF,αβ\⊗↔ ⊗; flush extra comma from front
⊗↑αXJOIN⊗↔⊗↔αβD ⊗; discard text between comma and incl colon
α+αXSSLINE⊗↔αF;αβ\εε⊗↔ ⊗; find matching semi (need not be present)
αXBREAK SRCHAR.⊗↔ ⊗; break ahead of where semi was
⊗↑αXJOIN⊗↔ ⊗; put intervening text on collecting line
⊗↔ ⊗; back to the working line
αβ⊗↓
αXDEFINE REPNAM⊗↔
⊗; if arg (rep cnt) > 1, allow any length local name and also quoted local names
⊗; if arg = 1, have REPNM6 save "@<host>" string for later use as default
α#αZREPNM0⊗↔ ⊗; assume RFC733 was called; parse a name
α#αZREPNM6⊗↔ ⊗; save hostname if #=1, else apply default
α+αXSSLINE⊗↔αZREPNM8⊗↔ ⊗; flush "@SAIL" and strip quotes if local
αXSTOPZERO⊗↔⊗↑⊗↔αF∧αβ\ αβ∞⊗↔ ⊗; change back special chars
⊗↑⊗↔αF∨αβ\,αβ∞⊗↔
⊗↑⊗↔αF∃αβ\:αβ∞⊗↔
⊗↑⊗↔αF≡∀αβ\@αβ∞⊗↔
αXSTOPONE⊗↔
αβ⊗↓
αXDEFINE REPNM0⊗↔
⊗; REPNM1-5,7 abort REPNM0 if successful, else leave junk line (except ##4-5,7)
αZREPNM1⊗↔αβD⊗↑ ⊗; look for "<NAME at SITE>" or "<NAME @ SITE>"
αZREPNM2⊗↔αβD⊗↑ ⊗; look for "NAME at SITE"
αZREPNM3⊗↔αβD⊗↑ ⊗; look for "NAME @ SITE"
αZREPNM4⊗↔ ⊗; try first alph string after space/tab
α-αCαEα#αZREPNM6⊗↔αβD ⊗; if #=1, find out if Remailed-from exists
α#αXARGUMENT RPDFLT⊗↔αZREPNM5⊗↔ ⊗; try first string if alph or quoted & arg>1 or def host known
α#αZREPNM7⊗↔ ⊗; if name was on Reply-To, don't argue!
αXSAY Sorry -- Can't find a name in the above line.⊗↔
αZREPLXX⊗↔ ⊗; abort
αβ⊗↓
αXDEFINE REPNM1⊗↔
αCαEα+αXSSLINE⊗↔αF<αβ\ε<⊗↔ ⊗; look for "<", delete portion to left
αXBREAK SRCHAR.⊗↔αβDαF<αβ\⊗↔ ⊗; also delete the "<"; SSLINE still okay
αF>αβ\>ε⊗↔ ⊗; look for ">", delete portion to right
αXBREAK SRCHAR.⊗↔⊗↔αβD⊗↑αF>αβ\⊗↔
αXSTOPZERO⊗↔⊗↑⊗↔α+αXSSLINE⊗↔ ⊗; if " at " appears, replace with "@"
αF at αβ\@⊗↔αXSTOPONE⊗↔
αZREPNMX⊗↔ ⊗; parse stuff around "@"; return if failed
αβ⊗↓
αXDEFINE REPNM2⊗↔
αCαEα+αXSSLINE⊗↔αF at αβ\@⊗↔ ⊗; look for " at " and replace with "@"
αZREPNMX⊗↔ ⊗; parse stuff around "@"; return if failed
αβ⊗↓
αXDEFINE REPNM3⊗↔
αCαEαZREPNMX⊗↔ ⊗; look for "@" and parse it if found
αβ⊗↓
αXDEFINE REPNMX⊗↔ ⊗; parse name and site from around "@"
αXINDENT -9999⊗↔α1αXTIN⊗↔α1αXSIN⊗↔ ⊗; strip leading/trailing blanks
⊗↑⊗↔α+αXSSLINE⊗↔ ⊗; make sure search will work right
αF@⊗↔αXIFLE SRCHAR.⊗↔ ⊗; make sure SOMETHING to left of "@"!
α1αXARGUMENT SRCHAR.⊗↔αXIFLT CHARS.⊗↔ ⊗; and something to right
αXBREAK SRCHAR.⊗↔ ⊗; get name by itself
αAαXJFILL 0,0,1⊗↔ ⊗; break into separate words
α-αAα+αCαβK ⊗; save just the last word
αXBREAK 1⊗↔ ⊗; separate "@" (we know there's more)
⊗↔αAαXJFILL⊗↔ ⊗; get site by itself (first word after "@")
αXSET REPTMP⊗↔αXARGUMENT ATTSIZ.⊗↔αXSUBTRACT REPTMP⊗↔
αXARGUMENT REPTMP⊗↔αCα0αA ⊗; discard all but first, then put it down
⊗; (might have done α0αC to drop it, hence α0αA (= nop) instead of αE)
α2⊗↑α3αXJOIN⊗↔ ⊗; put it together again
αXSSLINE⊗↔αF@⊗↔ ⊗; get SRCHAR pointing to "@" for REPNMQ
α-αβD ⊗; delete original line
α3αXABORT⊗↔ ⊗; abort REPNM0
αβ⊗↓
αXDEFINE REPNM4⊗↔
αCαXJFILL 0,0,1⊗↔ ⊗; break into words
αXSET REPTMP=ATTSIZ.⊗↔ ⊗; save number of words
αEα∞αZRPNM4A⊗↔ ⊗; look at each line for SAIL prog name
αβ⊗↓
αXDEFINE RPNM4A⊗↔
αZRPNM4B⊗↔ ⊗; check one line, return if failed
α⊗↔αβDαXSUBTRACT REPTMP⊗↔ ⊗; keep REPTMP as number of lines left
αXIFLE REPTMP⊗↔ ⊗; give up if REPTMP hits (or is set to) 0
αβ⊗↓
αXDEFINE RPNM4B⊗↔
α6α5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔ ⊗; look for first line that
α3α2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔ ⊗; starts with alphabetic
α2α6αXIFGE REPTM2⊗↔
⊗↔α-α1αXARGUMENT REPTMP⊗↔αβD ⊗; got it; ignore remaining lines
⊗↑αXSET REPTMP⊗↔ ⊗; set REPTMP to abort RPNM4A if we fail
αXIFLT CHARS.⊗↔α4αXIFGT CHARS.⊗↔ ⊗; must be either 2 or 3 chars
α αβ6αβ5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔ ⊗; second char alpha?
αβ3αβ2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔αβ2αβ6αXIFGE REPTM2⊗↔
α⊗=α⊗↑αβ6αβ5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔ ⊗; last char alpha?
αβ3αβ2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔αβ2αβ6αXIFGE REPTM2⊗↔
α⊗↔α-αβDα4αXABORT⊗↔ ⊗; a winner! abort all the way up to REPNM0
αβ⊗↓
αXDEFINE REPNM5⊗↔
⊗; permit this case only on "to" or "cc" or if def host known due to "remailed-from" line
α#αXSET REPTMP⊗↔α2αXIFLT REPTMP⊗↔
α-αCαXJFILL 0,0,1⊗↔ ⊗; break line into words
αXSET REPTMP=ATTSIZ.⊗↔ ⊗; save number of words
αE⊗↔α-α1αXARGUMENT REPTMP⊗↔αβD ⊗; delete all but the first word
⊗↑αZRPNM5A⊗↔ ⊗; check for quoted string (e.g., "#<file>")
α⊗↔αZRPNM5B⊗↔ ⊗; check for first-char = alph
αβD ⊗; no luck; flush line, let REPNM0 bitch
αβ⊗↓
αXDEFINE RPNM5A⊗↔
α3α4αXIFEQ ASCII.⊗↔ ⊗; make sure line starts with quote
α9α9αXIFGE CHARS.⊗↔ ⊗; local quoted names (#file, @file) always fairly short
α⊗=α⊗↑αβ3αβ4αXIFEQ ASCII.⊗↔ ⊗; make sure line ends with quote
α⊗↔α-αβDα3αXABORT⊗↔ ⊗; success! abort ourselves, REPNM5, and REPNM0
αβ⊗↓
αXDEFINE RPNM5B⊗↔
α6α5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔ ⊗; check for alph as in RPNM4B
α3α2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔α2α6αXIFGE REPTM2⊗↔ ⊗; allow lowercase
α-αβDα3αXABORT⊗↔ ⊗; alph it is, assume it's a forwarded name @SAIL
αβ⊗↓
αXDEFINE REPNM6⊗↔
⊗; if arg = 1, look for "@" and save hostname for later use as default
⊗; if arg > 1, look for "@" and if not found append default
α+αXSSLINE⊗↔α#αXSET REPTMP⊗↔α2αXMINIMUM REPTMP⊗↔
α-α1αXARGUMENT REPTMP⊗↔αXCASE RPNM6A RPNM6B⊗↔
αβ⊗↓
αXDEFINE RPNM6A⊗↔
αXSET RPDFLT⊗↔ ⊗; flag that no default known yet
αZRPNM6C⊗↔ ⊗; look for one on this line
αXSET REPTMP=LINE.⊗↔ ⊗; no luck, look for host Remailed-from
αCαEαLαXEMPTY⊗↔α+α0αXSSLINE⊗↔ ⊗; create junk line, restrict search to header
αLαXARGUMENT REPTMP⊗↔αZRPNM6D⊗↔ ⊗; RPNM6D might replace junk with new junk
αXARGUMENT REPTMP⊗↔αLαβD ⊗; whether or not that worked, we're through
αZRPNM6B⊗↔ ⊗; except we should apply Remailed-from host to this line, too!
αβ⊗↓
αXDEFINE RPNM6B⊗↔
αXIFNE RPDFLT⊗↔ ⊗; abort unless we know sender's host
α+αXSSLINE⊗↔αXSTOPZERO⊗↔⊗↔⊗↑αF@⊗↔ ⊗; look for "@" on this line
αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔ ⊗; exit if found
⊗↔αXATTACH RPHOST⊗↔αE⊗↑αXJOIN⊗↔ ⊗; else append default host text
αβ⊗↓
αXDEFINE RPNM6C⊗↔
α+αXSSLINE⊗↔⊗↔⊗↑αF@⊗↔ ⊗; look for "@", abort if none
αXBREAK SRCHAR.⊗↔⊗↔ ⊗; break line ahead of "@"
α1αXREDEFINE RPHOST⊗↔⊗↑αXJOIN⊗↔ ⊗; save "@<host>" in handy macro, rejoin
αXADD RPDFLT⊗↔ ⊗; flag that default host is now known
α2αXABORT⊗↔ ⊗; abort RPNM6A (don't look for Remailed-from)
αβ⊗↓
αXDEFINE RPNM6D⊗↔
αF⊗↓≡⊗↔Remailed-From:⊗↓⊗↔⊗↔ ⊗; look for first remailer, abort if none
αZRFC733⊗↔α#αL⊗↔αEα-αβD ⊗; parse RFC format, replace junk line with this
α2αZREPNM0⊗↔ ⊗; parse for name, don't restore spec chars
α#αXSET REPTMP⊗↔ ⊗; REPTMP used by parsing macros
αZRPNM6C⊗↔ ⊗; see if it has "@host" for us
αβ⊗↓
αXDEFINE REPNM7⊗↔
α#αXIFEQ RPRPTO⊗↔ ⊗; looking for sender's name in Reply-To field?
⊗↑αXINDENT -9999⊗↔α1αXTIN⊗↔α1αXSIN⊗↔
α2αXABORT⊗↔ ⊗; well, look no further!
αβ⊗↓
αXDEFINE REPNM8⊗↔
αXSTOPZERO⊗↔ ⊗; flush local address (BEFORE restoring "@"s!)
⊗↑⊗↔αF@SAILαβ\⊗↔⊗↑⊗↔αF@SU-AIαβ\⊗↔
⊗↑⊗↔αF@⊗↔αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔ ⊗; that's it unless no "@" now
α3αXIFLE CHARS.⊗↔ ⊗; first off, enough chars for quoted string?
α3α4αXIFEQ ASCII.⊗↔ ⊗; see if local name starts with quote
αXSTOPZERO⊗↔⊗↑⊗↔α∞αF"⊗↔ ⊗; yep, look for too many of them
αXARGUMENT NFOUND.⊗↔αβ* ⊗; now look for last on this line (at least 1!)
αXSTOPONE⊗↔α+α1αXARGUMENT SRCHAR.⊗↔αXIFEQ CHARS.⊗↔ ⊗; is last quote the last char?
αXBREAK SRCHAR.⊗↔αXBREAK 1⊗↔ ⊗; everything checks, discard quotes
αβD⊗↔αβD⊗↑α+αXSSLINE⊗↔
αβ⊗↓
αXDEFINE REPLST⊗↔
αXSET REPTOP⊗↔ ⊗; line from which to search, start at top
α∞αZRPLST1⊗↔ ⊗; process all the "to" or "cc" lines
α#αXMAXIMUM REPTOP⊗↔ ⊗; remember furthest we ever found a hit
αβ⊗↓
αXDEFINE RPLST1⊗↔
αXARGUMENT REPTOP⊗↔αL⊗↔⊗↑ ⊗; go to position of last line found
αXARGUMENT REPLN2⊗↔αXSSLINE⊗↔ ⊗; don't search original attached text
αZRPLSTF⊗↔ ⊗; look for appropriate header line
αXIFEQ NFOUND.⊗↔ ⊗; if none found, we're done
⊗↔αXSET REPTOP=LINE.⊗↔ ⊗; move down to actual line, save position
αZRFC733⊗↔ ⊗; pick up line, flush comments, etc.
αXARGUMENT REPLIN⊗↔αLαE ⊗; take it down to bottom
αXADD REPLIN⊗↔ ⊗; old attach buffer now further down
⊗↔α1αβ⊗↔,αβUαXJOIN⊗↔ ⊗; put comma on the end
α∞αZRPLST2⊗↔ ⊗; parse as many names as there are commas
αβDαXSUBTRACT REPLIN⊗↔ ⊗; delete whatever's left (probably null)
αβ⊗↓
αXDEFINE RPLST2⊗↔
α+αXSSLINE⊗↔αF,αβ\ ⊗↔αXBREAK SRCHAR.⊗↔ ⊗; break ahead of first comma
αZRPLS2A⊗↔ ⊗; process stuff ahead of comma
αβD ⊗; delete either blank line or junk line
αβ⊗↓
αXDEFINE RPLS2A⊗↔
α1αXTIN⊗↔α1αXSIN⊗↔ ⊗; get rid of trailing spaces
αXIFLE CHARS.⊗↔ ⊗; see if line had nothing but spaces
αXADD REPLIN⊗↔ ⊗; real text; account for BREAK in RPLST2
α2αZREPNAM⊗↔ ⊗; parse pre-comma text to form a name (2=arg, not rep cnt)
αZRPLSTI⊗↔ ⊗; add our special field name
αCαE ⊗; make a copy for RPLST2 to delete
αβ⊗↓
αXDEFINE REPSND⊗↔
αZRENTRY⊗↔
αZREPSN0⊗↔ ⊗; extra nesting level for quieter aborting
αZEXIT2⊗↔
αβ⊗↓
αXDEFINE REPLX2⊗↔ ⊗; error exit for REPSND
αXSSLINE⊗↔αZREXIT1⊗↔
α-α1αXARGUMENT MDEPTH.⊗↔αXABORT⊗↔
αβ⊗↓
αXDEFINE REPSN0⊗↔
αZREPSN1⊗↔ ⊗; find reply header; adjust REPLN2 & REPLIN if necessary
αZREPSN2⊗↔ ⊗; convert lines REPLN2 thru REPLIN-1 into mailing list
αZREPSN3⊗↔ ⊗; send the mail and clean up (leave reply text in undelete buf)
αβ⊗↓
αXDEFINE REPSN1⊗↔
αZRPSN1A⊗↔ ⊗; find "replying-to" line
⊗↔αXSET REPLN2=LINE.⊗↔ ⊗; remember its current position
αZRPSN1B⊗↔ ⊗; find "reply-text" line
⊗↔αXSET REPLIN=LINE.⊗↔ ⊗; remember it, too
αXARGUMENT REPLN2⊗↔αL ⊗; go to top of reply header
αXSET REPTMP=REPLIN⊗↔α1αXARGUMENT REPLN2⊗↔αXSUBTRACT REPTMP⊗↔
αXIFLE REPTMP⊗↔ ⊗; any lines between replying-to and reply-text?
αXARGUMENT REPTMP⊗↔αZRPSN1C⊗↔ ⊗; yes, check them for validity
αXARGUMENT REPLIN⊗↔αL ⊗; go to reply-text line
αXSTOPZERO⊗↔αXNONEMPTY⊗↔ ⊗; see if there's any text line after it
αXSTOPONE⊗↔αXARGUMENT LINE.⊗↔αXIFEQ REPLIN⊗↔ ⊗; return if there is
αβXSAY⊗↔αβXSAY Sorry -- No text found after "Reply-Text" line.⊗↔
αZREPLX2⊗↔
αβ⊗↓
αXDEFINE RPSN1A⊗↔
αXARGUMENT REPLN2⊗↔αL ⊗; go to approx loc of "replying-to" line
α+αXSSLINE⊗↔⊗↑ ⊗; first search just the one line
αXSTOPZERO⊗↔αF⊗↓≡⊗↔Replying-To:⊗↓⊗↔αXSTOPONE⊗↔
αXIFNE NFOUND.⊗↔ ⊗; exit if we found it
αXSTOPZERO⊗↔⊗↔αXEMPTY⊗↔ ⊗; try searching whole paragraph
α+α0αXSSLINE⊗↔α-αXEMPTY⊗↔αβ*
αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔ ⊗; again exit if found
αLαXARGUMENT LINES.⊗↔αXSSLINE⊗↔ ⊗; search whole page
αXSTOPZERO⊗↔αβ*αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
αβXSAY⊗↔αβXSAY Sorry -- Can't find the "Replying-To" line.⊗↔
αZREPLX2⊗↔
αβ⊗↓
αXDEFINE RPSN1B⊗↔
α!⊗↔α+α2αXSSLINE⊗↔ ⊗; go to end of "replying-to" graf; check next line
αXSTOPZERO⊗↔αF⊗↓≡⊗↔Reply-Text:≡⊗↔⊗↓⊗↔αXSTOPONE⊗↔
αXIFNE NFOUND.⊗↔ ⊗; exit if found header
αXARGUMENT REPLN2⊗↔αL ⊗; else try from "replying-to" to end
αXARGUMENT LINES.⊗↔αXSSLINE⊗↔αXSTOPZERO⊗↔αβ*αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
αβXSAY⊗↔αβXSAY Sorry -- Can't find the "Reply-Text" line.⊗↔
αZREPLX2⊗↔
αβ⊗↓
αXDEFINE RPSN1C⊗↔
αZRPSN1D⊗↔ ⊗; want to be able to abort one iteration at a time
αβ⊗↓
αXDEFINE RPSN1D⊗↔
⊗↔α+αXSSLINE⊗↔⊗↑ ⊗; go to next line and restrict searches to it
αXSTOPZERO⊗↔αXSET REPTMP⊗↔ ⊗; flag saying whether any search won
αF⊗↓≡⊗↔Also-To:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
αF⊗↓≡⊗↔Reply-cc:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
αF⊗↓≡⊗↔Reply-Subject:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
⊗↔αXSTOPONE⊗↔αXIFEQ REPTMP⊗↔ ⊗; abort if any of the searches won
α0αXNONEMPTY⊗↔ ⊗; empty lines are also legal in the header
αβXSAY⊗↔αβXSAY Sorry -- This line doesn't seem to belong in the reply header.⊗↔
αZREPLX2⊗↔
αβ⊗↓
αXDEFINE REPSN2⊗↔
αXSET REPTMP⊗↔ ⊗; number of "name" lines initially = 1 (replying-to)
αXARGUMENT REPLIN⊗↔αXSSLINE⊗↔ ⊗; stop searches at reply text
αXSTOPZERO⊗↔αF⊗↓≡⊗↔Reply-cc:⊗↓⊗↔ ⊗; set up search string
α1αXARGUMENT REPLN2⊗↔αL ⊗; collect all the cc lines (if any)
αXSTOPONE⊗↔α∞αZRPSN2A⊗↔
αXARGUMENT ATTSIZ.⊗↔αXADD REPTMP⊗↔ ⊗; remember total # of names
α1αXARGUMENT REPLN2⊗↔αLα0αA ⊗; drop them just below replying-to
αZRPSN2B⊗↔ ⊗; add "/cc" to first one if any
αXSTOPZERO⊗↔αF⊗↓≡⊗↔Also-To:⊗↓⊗↔ ⊗; do it again for also-to's
α1αXARGUMENT REPLN2⊗↔αLαXSTOPONE⊗↔α∞αZRPSN2A⊗↔
αXARGUMENT ATTSIZ.⊗↔αXADD REPTMP⊗↔
α1αXARGUMENT REPLN2⊗↔αLα0αA ⊗; drop them between replying-to and reply-cc's
⊗↑αXARGUMENT REPTMP⊗↔αZRPSN2C⊗↔ ⊗; convert field name on each line to comma
αXARGUMENT REPLN2⊗↔αLαXARGUMENT REPTMP⊗↔αXJOIN⊗↔ ⊗; make one big line
α-α1αXARGUMENT REPTMP⊗↔αXSUBTRACT REPLIN⊗↔ ⊗; reply-text thereby moved
αF,αβ\MAIL ⊗↔ ⊗; so much for the name list
αZRPSN2D⊗↔ ⊗; take care of reply-subject (if any)
αXARGUMENT REPLIN⊗↔αLαXNONEMPTY⊗↔ ⊗; go to top of reply text (probably subject)
αXSET REPTMP=REPLN2⊗↔α-α1αXARGUMENT LINE.⊗↔αXSUBTRACT REPTMP⊗↔
αXARGUMENT REPTMP⊗↔αβD ⊗; delete all lines between MAIL command and top of text
⊗↑ ⊗; leave us sitting on MAIL command line
αβ⊗↓
αXDEFINE RPSN2A⊗↔
⊗↑αβ*⊗↔α+αA
αβ⊗↓
αXDEFINE RPSN2B⊗↔
αXIFLT REPTMP⊗↔ ⊗; were there any attached reply-cc lines?
⊗↔α1αβ⊗↔/ccαβUαXJOIN⊗↔ ⊗; yes; add "/cc" to the first one
αβ⊗↓
αXDEFINE RPSN2C⊗↔
αF:αβ\ ⊗↔αXBREAK SRCHAR.⊗↔αβD ⊗; break off and discard reply header
αXINDENT -9999⊗↔ ⊗; flush leading spaces from name
αXINDENT 1⊗↔αF αβ\,⊗↔ ⊗; add a comma at the front
⊗↔ ⊗; move on to the next name
αβ⊗↓
αXDEFINE RPSN2D⊗↔
αXARGUMENT REPLIN⊗↔αXSSLINE⊗↔ ⊗; search from name list to reply-text
αF⊗↓≡⊗↔Reply-Subject:⊗↓⊗↔ ⊗; try to find subject (if none, don't object)
⊗↔αF:αβ\ ⊗↔αXBREAK SRCHAR.⊗↔αβD ⊗; flush header name
αXINDENT -9999⊗↔αAαXSUBTRACT REPLIN⊗↔ ⊗; pick up subject (moves reply-text line)
αXARGUMENT REPLIN⊗↔αL ⊗; go to reply-text header
αXNONEMPTY⊗↔αE ⊗; put subject down at top of actual text
αXARGUMENT REPLN2⊗↔αLαFMAILαβ\MAIL/SUBJ⊗↔ ⊗; make MAIL use top text line as subject
αβ⊗↓
αXDEFINE REPSN3⊗↔
αXSET REPTMP=CHARS.⊗↔ ⊗; length of MAIL command
α1α5α9αXDIVIDE REPTMP⊗↔ ⊗; assume E's limit is 158 chars
αXMINIMUM REPTMP⊗↔ ⊗; reduce to 0 or 1
αXARGUMENT REPTMP⊗↔αXCASE RPSN3A RPSN3B⊗↔ ⊗; do the right thing
αβK ⊗; put text into undelete buffer
αβ⊗↓
αXDEFINE RPSN3A⊗↔
⊗↔α1αβ⊗↔⊗⊗↔αβUα1αβ⊗↔⊗αXαβ3αβAαXREDEFINE REPTMP⊗↔αβK ⊗; put MAIL command into macro
αZREXIT1⊗↔ ⊗; prepare to exit
α∞αβ!αAαZREPTMP⊗↔ ⊗; pick up rest of page and mail it
αZRPSN3C⊗↔ ⊗; do a cancel if W flag was originally off
αβ⊗↓
⊗⊂ Here comes the real klugey part! If the MAIL command is too long to fit
in E's extended command buffer, we need to create a distribution-list file. This
leads to various problems, such as:
(1) We need to be sure we can write the file (i.e., that the directory won't be
protected against us), but we have no way of finding out the user's login ppn.
(2) We'd like to be sure the file won't conflict with any other file, in particular
that it won't overwrite a reply-dist file created by the same user from another
job.
(3) We'd like to delete the file afterward, but the only files E will delete are
MSG files on [2,2].
Crockish solution: Since everyone has write-access to [2,2], put the file there,
generating a random name of the form $XXXX$.MSG where the X's are based on the
amount of incore text, the page number, and the line number. A secondary problem
is making sure that MAIL is done with the file before we delete it. We execute a
null macro 15000 times, which seems to take a minimum of 1 compute sec, giving
MAIL time at least to start reading it, and then we wait until we're able to
OPEN the file again. ⊗⊃
αXDEFINE RPSN3B⊗↔
αXSET REPTMP=CORCHS.⊗↔α1αβ⊗↔αβ2αβZRPS3B1⊗↔ ⊗; first two chars are incore-#chars mod 676
αXSET REPTMP=CORLIN.⊗↔αβZRPS3B1⊗↔ ⊗; then comes incore-line mod 26
αXSET REPTMP=PAGE.⊗↔αβZRPS3B1⊗↔ ⊗; and finally page number mod 26
α⊗→αI⊗αε↓$α⊗=$↓.MSG[2,2]/C/Q⊗⊗↔αβAαXREDEFINE REPTMP⊗↔αβK ⊗; macro to go to random file
α∞αβ!αA ⊗; pick up all our stuff
αZRPSN3C⊗↔αZRPS3B2⊗↔ ⊗; cancel if appropriate
αZREPTMP⊗↔αE ⊗; go to temp file and drop everything
αF ⊗↔αXBREAK SRCHAR.⊗↔ ⊗; break off MAIL{/SUBJ} part
αI⊗αXα⊗=/LIST⊗⊗↔α⊗→αS/β⊗↔ ⊗; add /LIST switch and separate switch(es) from command
αXATTACH REPTMP⊗↔αE ⊗; fetch macro with this file's name
@αS/αK⊗↔αβUα3αAαXREDEFINE REPTMP⊗↔αβK ⊗; create <ctrl>XMAIL @<file>{/SUBJ}/LIST<cr>
⊗↔α∞αβ!αAαβ.αXCLOSE⊗↔ ⊗; pick up all but name-list and write it out
αZREPTMP⊗↔ ⊗; send the mail
αEαZREXIT1⊗↔ ⊗; put text down, prepare EXIT2 macro
α-αβDα1α5α0α0α0αZRPS3B3⊗↔ ⊗; delete mailing list line, twiddle thumbs
α∞αZRPS3B4⊗↔ ⊗; wait until OPEN command succeeds
α∞α∂αAα-αH ⊗; E will delete the file
αβ⊗↓
αXDEFINE RPS3B1⊗↔
αXSET REPTM2=REPTMP⊗↔αβ2αβ6αβXDIVIDE REPTMP⊗↔
αβ2αβ6αβXREMAINDER REPTM2⊗↔αβ6αβ5αβXADD REPTM2⊗↔αβXCHARACTER REPTM2⊗↔
αβ⊗↓
αXDEFINE RPS3B2⊗↔
αXIFEQ REPLW⊗↔αXIFEQ RMODE.⊗↔ ⊗; if W flag was on but /R mode...
αβXSAY⊗↔αβXSAY Warning -- Changing files temporarily; doing CANCEL due to /R mode.⊗↔
αXCANCEL⊗↔
αβ⊗↓
αXDEFINE RPS3B3⊗↔
⊗≠ ⊗; waste time to give MAIL chance to start reading dist list
αβ⊗↓
αXDEFINE RPS3B4⊗↔
αZRPS3B5⊗↔ ⊗; aborts us (and our rep count) if file opened
αβ⊗↓
αXDEFINE RPS3B5⊗↔
αXOPEN⊗↔
α2αXABORT⊗↔
αβ⊗↓
αXDEFINE RPSN3C⊗↔
αXIFNE REPLW⊗↔αXCANCEL⊗↔ ⊗; undo everything if W flag was off when REPLY called
αβ⊗↓
αXDEFINE CCME⊗↔
αZRENTRY⊗↔
αZCCME0⊗↔ ⊗; extra nesting level for quieter aborting
αZEXIT2⊗↔
αβ⊗↓
αXDEFINE CCME0⊗↔
αXSET REPTMP=LINE.⊗↔ ⊗; remember where we were
αZRPSN1A⊗↔ ⊗; look for "replying-to" line
⊗↔⊗↔αβ⊗↔Reply-cc: .α⊗↔ ⊗; add cc-to-oneself
αXSET REPTM2=REPTMP⊗↔αXARGUMENT LINE.⊗↔αXDIVIDE REPTM2⊗↔ ⊗; is REPTMP≥LINE.?
αXMINIMUM REPTM2⊗↔αXARGUMENT REPTM2⊗↔αXADD REPTMP⊗↔ ⊗; if so, incr
αXARGUMENT REPTMP⊗↔αL ⊗; return to original line
αZREXIT1⊗↔
αβ⊗↓
αXDEFINE OLDMSG⊗↔
αZRENTRY⊗↔
αZOLDMS0⊗↔ ⊗; extra nesting level for quieter aborting
αZEXIT2⊗↔
αβ⊗↓
αXDEFINE OLDMS0⊗↔
αZRPSN1A⊗↔ ⊗; look for "replying-to" line
⊗↔⊗↔α-α∞αβ!αC ⊗; copy it & everything above (in incore page)
⊗; (include "replying-to" line to guarantee at least one line, else αβ! barfs)
αXINDENT S 2⊗↔αXSIN⊗↔ ⊗; indent by 2 and change tabs to spaces
α∞αLαEα1αβ⊗↔α7α0-α⊗→+⊗↔ ⊗; append to reply-text, put line across top
α∞αZOLDMS1⊗↔α7α0-α⊗→+α⊗↔ ⊗; put bar down left and line at bottom
α-αβD⊗↑αZOLDMS3⊗↔ ⊗; flush "replying-to" & blank above it (if any)
α∞αLαZREXIT1⊗↔ ⊗; leave cursur at bottom
αβ⊗↓
αXDEFINE OLDMS1⊗↔
αZOLDMS2⊗↔ ⊗; OLDMS2 handles empty lines
α0αXNONEMPTY⊗↔ ⊗; make sure we stop at incore pagemark
αF αβ\|⊗↔α1αXTIN⊗↔⊗↔ ⊗; if not empty, add spike and move on
αβ⊗↓
αXDEFINE OLDMS2⊗↔
α0αXEMPTY⊗↔ ⊗; note that end-of-page is not empty
α⊗↔ ⊗; create space for OLDMS1 to change
αβ⊗↓
αXDEFINE OLDMS3⊗↔
αXIFEQ CHARS.⊗↔αβD ⊗; delete line if contains only a "|"
αβ⊗↓
αXDEFINE TOLIST⊗↔
αZRENTRY⊗↔
αZTOLST0⊗↔ ⊗; extra nesting level for quieter aborting
αZEXIT2⊗↔
αβ⊗↓
αXDEFINE TOLST0⊗↔
αZRPSN1A⊗↔⊗↔⊗↔ ⊗; look for "replying-to", go to line after
αZTOLST1⊗↔ ⊗; change it to "replying-to"
α-αβD ⊗; flush old line
αZREXIT1⊗↔
αβ⊗↓
αXDEFINE TOLST1⊗↔
α+αXSSLINE⊗↔αXSTOPZERO⊗↔ ⊗; prepare for failing substitutions
αFAlso-To:αβ\Replying-To:⊗↔αXSTOPONE⊗↔αXIFNE NSUBST.⊗↔ ⊗; abort if okay
αXSTOPZERO⊗↔αFReply-cc:αβ\Replying-To:⊗↔αXSTOPONE⊗↔αXIFNE NSUBST.⊗↔
αβXSAY Sorry -- Line after "Replying-To" isn't an address line.⊗↔
⊗↑αZREPLX2⊗↔
αβ⊗↓
αxsay REPLY CCME TOLIST OLDMSG ⊗↔
⊗⊂ And we'll be needing ENTRY/EXIT macros: ⊗⊃ αXEXECUTE EINIT.CMD[1,3](13)⊗↔